package com.pansoft.nfc;

import android.app.Activity;
import android.content.Context;

import com.efounder.chat.utils.AESSecretUtil;
import com.efounder.constant.EnvironmentVariable;
import com.efounder.utils.ResStringUtil;
import com.pansoft.nfc.mifare.Common;
import com.pansoft.openplanet.R;
import com.pansoft.openplanet.bean.Account;
import com.pansoft.openplanet.bean.CardBean;
import com.pansoft.openplanet.bean.CardWalletInfo;
import com.pansoft.openplanet.constant.IPAssetsConstant;
import com.pansoft.openplanet.db.AccountDao;
import com.pansoft.openplanet.util.TCAccountManager;
import com.utilcode.util.LogUtils;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * nfc操作的通用封装类
 * 主要对位置，钱包等信息操作
 *
 * @author wang
 */
public class NfcCommonUtils {

    /**
     * 根据卡片已有的钱包位置，确定下一个钱包写入的位置
     *
     * @return 写入的区块位置position，如果超出返回-1
     */
    public static int getReadWalletPosition(String address, List<CardWalletInfo> list) {
        for (CardWalletInfo c :
                list) {
            if (c.getAddress().equals(address)) {
                return c.getInCardPosition();
            }
        }
        return -1;
    }

    /**
     * 根据卡片已有的钱包位置，确定下一个钱包写入的位置
     *
     * @return 写入的区块位置position，如果超出返回-1
     */
    public static int getInsertWalletPosition(int maxSector, List<CardWalletInfo> list) {
        //如果sector == 16， 那么只能存两个钱包，
        //如果sector == 40， 那么能存13个钱包
        //现在使用的一般都是4K卡，40个扇区
        int num = 13;
        if (maxSector == 16) {
            num = 2;
        }
        for (int i = 0; i < num; i++) {
            int count = 0;
            for (CardWalletInfo c :
                    list) {
                count++;
                if (c.getInCardPosition() != i) {
                    if (count == list.size()) {
                        return i;
                    }
                    continue;
                }
                break;
            }
        }
        return -1;
    }

    /**
     * 根据钱包位置确定读取的block
     * 4K卡，根据存储结构，7-31 sector，每5个存储一个钱包
     * 每个sector有4个block
     * 32-39 sector，每一个存储一个钱包
     * 每个sector有16个block
     *
     * @param position 钱包位置
     * @return block 编号
     */
    public static int getBlockByPosition(int position) {
        if (position < 5) {
            return ((position * 5) + 7) * 4;
        } else {
            return (position - 5) * 16 + 128;
        }
    }

    /**
     * 根据钱包位置确定读取的sector
     * 4K卡，根据存储结构，7-31 sector，每5个存储一个钱包
     * 32-39 sector，每一个存储一个钱包
     *
     * @param position 钱包位置
     * @return sector 编号
     */
    public static int getSectorByPosition(int position) {
        if (position < 5) {
            return (position * 5) + 7;
        } else {
            return position + 27;
        }
    }

    /**
     * 处理从卡上读到的钱包数据
     * 组织到cardBean里
     *
     * @param context   context
     * @param positions 卡片上的位置信息，每个钱包所在的位置
     * @param data      钱包信息
     * @param cardBean  cardBean
     * @return cardBean
     */
    public static void handleCardWalletData(Context context, String[] positions, String[] data, CardBean cardBean) {
        //取出在卡片上的位置和钱包信息
        //生成bean，存储到数据库，读卡完成
        List<CardWalletInfo> walletInfoList = new ArrayList<>();
        //资产的钱包，如果没有，同步生成
        List<Account> accounts = new ArrayList<>();
        for (int i = 0; i < positions.length; i++) {
            try {
                String walletInfo = data[i];
                //长度+chainId+长度+addr+长度+privateKey
                //第3、4位是chainId
                String chainId = new String(Common.hexStringToByteArray(walletInfo.substring(2, 4)),
                        StandardCharsets.UTF_8).trim();
                //5、6位是地址长度
                int addrLength = Integer.parseInt(walletInfo.substring(4, 6), 16);
                //取地址
                String addr = new String(Common.hexStringToByteArray(walletInfo.substring(6, 6 + addrLength)),
                        StandardCharsets.UTF_8).trim();
                CardWalletInfo cardWalletInfo = new CardWalletInfo();
                cardWalletInfo.setInCardPosition(Integer.valueOf(positions[i]));
                cardWalletInfo.setAddress(addr);
                cardWalletInfo.setChainId(Integer.valueOf(chainId));
                Account account = new AccountDao(context).getAccount(addr);
                if (account != null) {
                    cardWalletInfo.setWalletName(account.getAcccountName());
                    cardWalletInfo.setWalletAvatar(account.getAccountAvatar());
                } else {
                    account = new Account();
                    account.setEnable(true);
                    account.setAcccountName(cardWalletInfo.getWalletName());
                    account.setAccountAvatar(cardWalletInfo.getWalletAvatar());
                    //冷钱包2
                    account.setAccountType(Account.ACCOUNT_TYPE_COLD);
                    account.setAddress(cardWalletInfo.getAddress());
                    account.setColdWalletCardUid(cardBean.getUid());
                    //btc 1 ,eth 2
                    account.setBlockChainName(chainId.equals("1") ? IPAssetsConstant.ChainEnum.BTC.chainName
                            : IPAssetsConstant.ChainEnum.ETH.chainName);
                    new AccountDao(context).insertOrReplace(account);
                    accounts.add(account);
                }
                //上传到资产
                new TCAccountManager(context).addChildToServer(context, accounts);
                walletInfoList.add(cardWalletInfo);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        cardBean.setWalletInfoList(walletInfoList);
        cardBean.setEnable(true);
    }

    /**
     * 处理0扇区，存储的是卡号信息
     */
    public static boolean handleUidStartData(final Context context, String readContent) {
        try {
            LogUtils.d("头部uid", readContent);
            readContent = readContent.replace((" "), "").replace("\n", "");
            //uid卡号
            String uid = readContent.substring(0, 32);
            LogUtils.d("UID--", uid);
            //卡所属APP，不同APP的的卡不同互用，防止出现资产同步问题
            //TP-TurboPay, MP-MulePay, TC-Telecomm
            String cardApphex = readContent.substring(32, 36);
            final String cardApp = new String(Common.hexStringToByteArray(cardApphex), StandardCharsets.UTF_8).trim();
            if (!EnvironmentVariable.getProperty("APPID").equals(getCardAppId(cardApp))) {
                //卡片不属于这个APP
                ((Activity) context).runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        NfcAlertUtils.showWrongMsg((Activity) context,
                                String.format(ResStringUtil.getString(R.string.star_asset_card_type_wrong), cardApp));
                    }
                });
                return false;
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 处理1扇区数据，存储卡片PIN码
     * 返回解密之后的密码
     */
    public static String handleSecretKeyData(String password) {
        //读取1扇区，存有PIN密码，使用AES加密之后的
        password = password.replace((" "), "").replace("\n", "");
        password = new String(Common.hexStringToByteArray(password), StandardCharsets.UTF_8).trim();
        //验证密码，如果密码错误，返回错误
        AESSecretUtil aesSecretUtil = new AESSecretUtil(Common.NFC_PASSWORD_SECRET_KEY);
        password = aesSecretUtil.decrypt(password);
        return password;
    }

    /**
     * 组织更改PIN的hex十六进制字符串
     * @param pin 要改成的pin
     * @return hex
     */
    public static String getChangePinHex(String pin) {
        AESSecretUtil aesSecretUtil = new AESSecretUtil(Common.NFC_PASSWORD_SECRET_KEY);
        String newPass = Common.byte2HexString(aesSecretUtil.encrypt(pin).getBytes());
        while (newPass.length() < 16 * 2 * 3) {
            newPass = newPass.concat("0");
        }
        return newPass;
    }

    /**
     * 根据卡号前缀，获取对应的APPID
     *
     * @param cardApp 前缀
     * @return APPID
     */
    private static String getCardAppId(String cardApp) {
        if ("TP".equals(cardApp)) {
            return "OSPOpenPlanet";
        } else if ("MP".equals(cardApp)) {
            return "MulePay";
        } else if ("TC".equals(cardApp)) {
            return "Telecomm";
        } else {
            return "OSPOpenPlanet";
        }
    }
}
